﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.XPath;

namespace PDO.Utilities
{
    public static class CommonConfigHelper
    {
        ///Config file structure
        ///
        /// Configuration strings used by the local host to connect to a master host
        /// CIS.Server.Remote.Address
        /// CIS.Server.Remote.Port
        /// 
        /// Configuration strings used by the client to connect to a local or master host.
        /// Port is also used by the local host to host its services on.
        /// CIS.Client.Remote.Address
        /// CIS.Client.Remote.Port
        
        /// <summary>
        /// 
        /// </summary>

        private const string FILE_NAME = "common.config";

        private const string SERVER_PORT_CONFIGURATION_KEY = "CIS.Server.Remote.ServerPort";
        private const string SERVER_ADDRESS_CONFIGURATION_KEY = "CIS.Server.Remote.ServerAddress";
        private const string SERVER_PORT_DEFAULT = "8888";
        private const string SERVER_ADDRESS_DEFAULT = "localhost";

        private const string CONFIGURE_CONFIGURATION_KEY = "CIS.Configure";
        private const string ONLINE_ONLY_CLIENT_MODE_KEY = "CIS.Client.OnlineOnly";
        
        private const string CLIENT_SERVER_ADDRESS_KEY = "CIS.Client.Remote.ServerAddress";
        private const string CLIENT_SERVER_PORT_KEY = "CIS.Client.Remote.ServerPort";
        
        private const string CLIENT_SERVER_PORT_DEFAULT = "7777";
        private const string CLIENT_SERVER_ADDRESS_DEFAULT = "localhost";

       

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static bool MarkAsConfigured()
        { 
            // remove the configuration flag from the specified common.config file
            XmlDocument doc = new XmlDocument();
            doc.Load(FILE_NAME);
            try
            {
                XmlNode node = doc.SelectSingleNode(string.Format("/appSettings/add[@key='{0}']", CONFIGURE_CONFIGURATION_KEY));
                if (node != null)
                {
                    node.ParentNode.RemoveChild(node);
                }
            }
            catch (XPathException)
            {
                return false;
            }

            doc.Save(FILE_NAME);
            return true;
        }

        public static bool WriteServerConfiguration(string address, string port)
        {
            // remove the configuration flag from the specified common.config file
            XmlDocument doc = new XmlDocument();
            doc.Load(FILE_NAME);
            try
            {
                XmlNode node;
                if (IsOnlineOnlyClient)
                {
                    // Remove <add key=CIS.Client.Port />
                    node = doc.SelectSingleNode(string.Format("/appSettings/add[@key='{0}']", CLIENT_SERVER_ADDRESS_KEY));
                    if (node != null)
                    {
                        node.ParentNode.RemoveChild(node);
                    }
                    // Remove <add key=CIS.Client.Port />
                    node = doc.SelectSingleNode(string.Format("/appSettings/add[@key='{0}']", CLIENT_SERVER_ADDRESS_KEY));
                    if (node != null)
                    {
                        node.ParentNode.RemoveChild(node);
                    }
                }
                else
                {
                    // Remove <add key=CIS.Server.Remote.ServerPort />
                    node = doc.SelectSingleNode(string.Format("/appSettings/add[@key='{0}']", SERVER_PORT_CONFIGURATION_KEY));
                    if (node != null)
                    {
                        node.ParentNode.RemoveChild(node);
                    }

                    // Remove <add key=CIS.Server.Remote.ServerAddress />
                    node = doc.SelectSingleNode(string.Format("/appSettings/add[@key='{0}']", SERVER_ADDRESS_CONFIGURATION_KEY));
                    if (node != null)
                    {
                        node.ParentNode.RemoveChild(node);
                    }
                }
                

                // Insert the appropriate child nodes
                node = doc.SelectSingleNode("/appSettings");
                if (node != null)
                {
                    // When an online client is specified, write strings specific to the onlineonly configuration
                    // Online:
                    //  ClientPort
                    //  ClientAddress
                    // Offline:
                    //  ServerPort
                    //  ServerAddress
                    if (IsOnlineOnlyClient)
                    {                        
                        XmlElement element = CreateConfigurationEntry(doc, CLIENT_SERVER_PORT_KEY, port);
                        node.AppendChild(element);
                        element = CreateConfigurationEntry(doc, CLIENT_SERVER_ADDRESS_KEY, address);
                        node.AppendChild(element);
                    }
                    else
                    {
                        XmlElement element = CreateConfigurationEntry(doc, SERVER_PORT_CONFIGURATION_KEY, port);
                        node.AppendChild(element);
                        element = CreateConfigurationEntry(doc, SERVER_ADDRESS_CONFIGURATION_KEY, address);
                        node.AppendChild(element);
                    }
                }
            }
            catch (XPathException)
            {
                return false;
            }

            doc.Save(FILE_NAME);
            return true;
        }

        private static XmlElement CreateConfigurationEntry(XmlDocument doc, string key, string value)
        {
            XmlElement element = doc.CreateElement("add");
            XmlAttribute attr = doc.CreateAttribute("key");
            attr.Value = key;
            element.Attributes.Append(attr);

            attr = doc.CreateAttribute("value");
            attr.Value = value;
            element.Attributes.Append(attr);

            return element;
        }

        /// <summary>
        /// Determinds if the client is configured to be online only. This method returns 'false' by default.
        /// </summary>
        public static bool IsOnlineOnlyClient
        {
            get
            {
                return ConfigurationHelper.KeyExists(ONLINE_ONLY_CLIENT_MODE_KEY);
            }
        }

        public static bool IsConfigured
        {
            get
            {
                return !ConfigurationHelper.KeyExists(CONFIGURE_CONFIGURATION_KEY);
            }
        }

        public static string ServerRemoteServerAddress
        {
            get
            {
                return ConfigurationHelper.ReadConfigurationString(SERVER_ADDRESS_CONFIGURATION_KEY, SERVER_ADDRESS_DEFAULT);
            }
        }

        public static string ServerRemoteServerPort
        {
            get
            {
                return ConfigurationHelper.ReadConfigurationString(SERVER_PORT_CONFIGURATION_KEY, SERVER_PORT_DEFAULT);
            }
        }

        public static string ClientRemoteServerAddress
        {
            get
            {
                return ConfigurationHelper.ReadConfigurationString(CLIENT_SERVER_ADDRESS_KEY, CLIENT_SERVER_ADDRESS_DEFAULT);
            }
        }

        public static string ClientRemoteServerPort
        {
            get
            {
                return ConfigurationHelper.ReadConfigurationString(CLIENT_SERVER_PORT_KEY, CLIENT_SERVER_PORT_DEFAULT);
            }
        }
    }
}
